import re

from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render, redirect

from myapp.ALL_VAR import *
from myapp.GM_do_step import *



def build(user_data, steps):
    # 声明最终返回值
    res = {}
    # 检查数据 或 打补丁
    if not user_data or steps == []:
        res["code"] = -1
        res["msg"] = "数据或步骤丢失"
        return res


    # 替换全局变量ALL_VAR
    user_data = replace_user_data(user_data)

    # 遍历所有步骤
    for step in steps:
        # 是否执行
        if step.ifdo:
            for retry_count in range(int(step.retry) + 1):

                # 前延迟
                time.sleep(int(step.delay_before))
                try:
                ## 把步骤骨架steps和用户数据user_data进行融合 {# #}
                    if step.method == 'r':
                        # url
                        pars_url_userdata = re.findall(r'{#(.*?)#}',str(step.request_url))
                        for puu in pars_url_userdata:
                            step.request_url = step.request_url.replace('{#%s#}'%puu,user_data[puu])
                        # header
                        pars_header_userdata = re.findall(r'{#(.*?)#}', str(step.request_headers))
                        for phu in pars_header_userdata:
                            step.request_headers = step.request_headers.replace('{#%s#}' % phu, user_data[phu])
                        # body
                        pars_body_userdata = re.findall(r'{#(.*?)#}', str(step.request_body))
                        for pbu in pars_body_userdata:
                            step.request_body = step.request_body.replace('{#%s#}' % pbu, user_data[pbu])
                    elif step.method == 's':
                        # body
                        pars_body_userdata = re.findall(r'{#(.*?)#}', str(step.sql_body))
                        for pbu in pars_body_userdata:
                            step.sql_body = step.sql_body.replace('{#%s#}' % pbu, user_data[pbu])
                    elif step.method == 'l':
                        # body
                        pars_body_userdata = re.findall(r'{#(.*?)#}', str(step.linux_body))
                        for pbu in pars_body_userdata:
                            step.linux_body = step.linux_body.replace('{#%s#}' % pbu, user_data[pbu])
                    else:
                        res['code'] = -999
                        res['msg'] = '步骤类型错误'
                        return res

                    ## 把步骤骨架steps和动态临时变量(前面步骤提取出来的)融合  [# #]
                    if step.method == 'r':
                        # url
                        pars_url_tmpdata = re.findall(r'\[#(.*?)#]', str(step.request_url))
                        for put in pars_url_tmpdata:
                            step.request_url = step.request_url.replace('[#%s#]' % put, eval(put))
                        # header
                        pars_header_tmpdata = re.findall(r'\[#(.*?)#]', str(step.request_headers))
                        for pht in pars_header_tmpdata:
                            step.request_headers = step.request_headers.replace('[#%s#]' % pht, eval(pht))
                        # body
                        pars_body_tmpdata = re.findall(r'\[#(.*?)#]', str(step.request_body))
                        for pbt in pars_body_tmpdata:
                            step.request_body = step.request_body.replace('[#%s#]' % pbt, eval(pbt))
                    elif step.method == 's':
                        # body
                        pars_body_tmpdata = re.findall(r'\[#(.*?)#]', str(step.sql_body))
                        for pbt in pars_body_tmpdata:
                            step.sql_body = step.sql_body.replace('\[#%s#]' % pbt, eval(pbt))
                    elif step.method == 'l':
                        # body
                        pars_body_tmpdata = re.findall(r'\[#(.*?)#]', str(step.linux_body))
                        for pbt in pars_body_tmpdata:
                            step.linux_body = step.linux_body.replace('\[#%s#]' % pbt, eval(pbt))

                    #### 调用组件执行步骤
                    if step.method == 'r':
                        if step.request_group:


                            # step_res = do_request(step, step.request_group)
                            if step.request_group not in ["",' ',None, 0]: # 检查数据库登录态分组字段是否不为空
                                # 如果有分组的时候
                                session_x = 'session_' + str(step.request_group)
                                try: # 已有
                                    eval(session_x)  # 对拼接的session求值，判断是否是第一次, test3 已测试
                                except: # 首次
                                    exec("%s = requests.session()" %session_x)   # session_1 = requests.session()
                                    exec("%s.keep_alive = False" % session_x)   # 这里为了分组，不能一直保持长链接
                            step_res = do_request(step, session=eval(session_x))
                        else:
                            step_res = do_request(step)

                    elif step.method == 's':
                        step_res = do_sql(step)

                    elif step.method == 'l':
                        step_res = do_linux(step)

                    print(f" 执行后的结果step_res ==> {step_res}")

                    # 断言拦截，通过状态码 判断步骤执行结果是否成功
                    if step_res["code"] != 0:
                        res["code"] = step_res["code"]
                        res["msg"] = step_res["msg"]
                        return res


                    # 断言结果 (这个断言其实效果相当于替下一步之后的步骤进行一个检查而已。
                    # 如果这个接口失败了，咱们后面就不执行了，他的实际的作用并没有多大，它只是一个流程上的规范性的作用。)
                    # 设计到数据库里提取出来的字段进行判断，就必须要考虑2个特殊值，一个是空，一个是None
                    if step.method == 'r':
                        if step.request_assert_str in [None, "", "None"] or step.request_assert_str in str(step_res["data"].text): # do_step.py 返回的是data 是整个res！！！
                            pass
                        else:
                            raise Exception("断言失败") # 人工引发异常，进入try except
                            # res["code"] = -2
                            # res["msg"] = "断言失败"
                            # return res
                    elif step.method == 's':
                        if step.sql_assert_str in [None, "", "None"] or step.sql_assert_str in str(step_res['data']):
                            pass
                        else:
                            raise Exception("断言失败")
                            # res["code"] = -2
                            # res["msg"] = "断言失败"
                            # return res

                    elif step.method == 'l':
                        if step.linux_assert_str in [None, "", "None"] or step.linux_assert_str in str(step_res['data']):
                            pass
                        else:
                            raise Exception("断言失败")
                            # res["code"] = -2
                            # res["msg"] = "断言失败"
                            # return res


                    # 提取变量持久化
                    if step.method == 'r':
                        ## 正则提取
                        if step.request_extract_re not in [None,'','None']:
                            extracts = step.request_extract_re.split('|||')
                            for ex in extracts:
                                key = ex.split('=')[0].strip()
                                value = ex.split('=')[1].strip()
                                re_value = re.findall(r'%s'%value,str(step_res['data'].text))[0]
                                exec("%s = %s"%(key,repr(re_value)))
                        # 路径提取 gzh_name = ./data/gzh ||| gzh_id = ./data/id
                        if step.request_extract_path not in [None,'','None']:
                            extracts = step.request_extract_path.split('|||')
                            for ex in extracts:
                                key = ex.split('=')[0].strip()
                                value = ex.split('=')[1].strip()
                                paths = value.split("/")
                                path_value = step_res['data'].json()    # 路径提取主要是针对json数据类型的返回值
                                for ps in paths:
                                    if ps not in ['.','',' ']:
                                        path_value = path_value[ps]
                                exec("%s = %s" % (key, repr(path_value)))

                        # print(eval("gzh_name"), eval("gzh_id"))
                    #     gzh_name=0/2 ||| gzh_id = 1/3
                    elif step.method == 's':
                        if step.sql_extract_index not in [None,'','None']:
                            extracts = step.sql_extract_index.split('|||')
                            for ex in extracts:
                                key = ex.split('=')[0].strip()
                                value = ex.split('=')[1].strip()
                                row = int(value.split("/")[0])
                                column = int(value.split("/")[1])
                                index_value = step_res['data'][row][column]
                                exec("%s = %s" % (key, repr(index_value)))
                        print(eval("gzh_name"), eval("gzh_id"))

                    elif step.method == 'l':
                        if step.linux_extract_re not in [None,'','None']:
                            extracts = step.linux_extract_re.split('|||')
                            for ex in extracts:
                                key = ex.split('=')[0].strip()
                                value = ex.split('=')[1].strip()
                                re_value = re.findall(r'%s'%value,str(step_res["data"]))[0]
                                exec("%s = %s"%(key,repr(re_value)))


                    # 提取变量到最终返回
                    ## 正则提取
                    if step.final_res_re not in [None,'','None']:
                        extracts = step.final_res_re.split('|||')
                        for ex in extracts:
                            key = ex.split('=')[0].strip()
                            value = ex.split('=')[1].strip()
                            re_value = re.findall(r'%s'%value,str(step_res['data'].text))[0]
                            res[key] = re_value

                except Exception as e:
                    import traceback
                    res["ErrorMsg"] = str(traceback.format_exc())
                    continue

                # 打破重试循环
                break
            else:
                res["code"] = -999
                res["msg"] = "构造失败" + step.name
                return res


            # 后延迟
            time.sleep(int(step.delay_after))

    # 返回最终结果
    res["code"] = 0
    res["msg"] = "构造成功"
    return res


